package util;

import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

final class USClothingSize extends ClothingSize {
	public final static USClothingSize[] FEMALE_SIZES = {
			new USClothingSize("XL", "X-Large"),
			new USClothingSize("L", "Large"),
			new USClothingSize("M", "Medium"),
			new USClothingSize("S", "Small"),
			new USClothingSize("XS", "X-Small") };
	public final static USClothingSize[] MALE_SIZES = {
			new USClothingSize("XXL", "X-X-Large"),
			new USClothingSize("XL", "X-Large"),
			new USClothingSize("L", "Large"),
			new USClothingSize("M", "Medium"),
			new USClothingSize("S", "Small"),
			new USClothingSize("XS", "X-Small") };;

	public final static USClothingSize[] FEMALE__SIZES = {
			new USClothingSize("XL", "X-Large"),
			new USClothingSize("L", "Large"),
			new USClothingSize("M", "Medium"),
			new USClothingSize("S", "Small"),
			new USClothingSize("XS", "X-Small") };
	private final static Set<String> ALL_SIZES;

	private USClothingSize(String value, String des) {
		super(Locale.US, value, des);
	}

	public static USClothingSize instanceOf(String value, String des)
			throws IllegalArgumentException {
		if (!oneOf(value)) {
			throw new IllegalArgumentException("Value: " + value
					+ " is not one size of clothing'");
		}
		return new USClothingSize(value, des);
	}

	static {
		ALL_SIZES = new HashSet<String>();
	}

	protected static void buildSizes(USClothingSize[] values) {
		for (int i = 0; i < values.length; i++) {
			ALL_SIZES.add(values[i].getValue());
		}
	}

	public static boolean oneOf(String value) {
		return ALL_SIZES.contains(value);
	}

	public static void main(String[] args) {
		Size s = USShoseSize.instanceOf(19);

	}
}

final class USShoseSize extends ShoesSize {
	private static final double[] FEMALE_STANDARD = { 5, 5.5, 6, 6.5, 7, 7.5,
			8, 8.5, 9, 10, 10.5, 11, 11.5, 12, 12.5, 13, 13.5 };
	private static final double[] MALE_STANDARD = { 6, 6.5, 7, 7.5, 8, 8.5, 9,
			10, 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14 };
	private static final double[] CHILD_STANDARD = { 8.5, 9, 9.5, 10, 10.5, 11,
			11.5, 12, 12.5, 13, 13.5, 1, 1.5, 2, 2.5, 3 };
	public final static Size[] FEMALE_SIZES;
	public final static Size[] MALE_SIZES;
	public final static Size[] CHILD_SIZES;
	private final static Set<Double> ALL_SIZES;

	private USShoseSize(double value) {
		super(Locale.US, String.valueOf(value));
	}

	public static USShoseSize instanceOf(double value)
			throws IllegalArgumentException {
		if (!oneOf(value)) {
			throw new IllegalArgumentException("Value: " + value
					+ " is not one size of shoes'");
		}
		return new USShoseSize(value);
	}

	static {
		ALL_SIZES = new HashSet<Double>();
		FEMALE_SIZES = buildSizes(FEMALE_STANDARD);
		MALE_SIZES = buildSizes(MALE_STANDARD);
		CHILD_SIZES = buildSizes(CHILD_STANDARD);
	}

	protected static Size[] buildSizes(double[] values) {
		Size[] sizes = new Size[values.length];
		for (int i = 0; i < values.length; i++) {
			sizes[i] = new USShoseSize(values[i]);
			ALL_SIZES.add(values[i]);
		}
		return sizes;
	}

	public static boolean oneOf(double value) {
		return ALL_SIZES.contains(value);
	}

	public static void main(String[] args) {
		Size s = USShoseSize.instanceOf(19);

	}
}

abstract class ClothingSize extends Size {
	private final String value;
	private final String description;

	public ClothingSize(String value, String des) {
		super();
		this.value = value;
		this.description = des;
	}

	public ClothingSize(Locale locale, String value, String des) {
		super(locale);
		this.value = value;
		this.description = des;
	}

	public String getValue() {
		return value;
	}

	public String getDescription() {
		return description;
	}

}

abstract class ShoesSize extends Size {
	private final String value;

	public ShoesSize(String value) {
		super();
		this.value = value;
	}

	public ShoesSize(Locale locale, String value) {
		super(locale);
		this.value = value;
	}

	public String getValue() {
		return this.value;
	}
}

public abstract class Size {

	private Locale locale;

	public Size() {
		this.locale = Locale.getDefault();
	}

	public Size(Locale locale) {
		this.locale = locale;
	}

	protected Locale getLocale() {
		return this.locale;
	}

	public abstract String getValue();

}
